using System.Web.Mvc;
using Kym.Core;
using MvcContrib;
using MvcContrib.Attributes;
using NHibernate.Criterion;
using ProjectBase.Core;
using Rhino.Commons;

namespace Kym.Web.Controllers
{
    public class ContactsController : ConventionController
    {
        private readonly IRepository<Contact> contactRepository;
        private readonly IRepository<Message> messageRepository;

        public ContactsController(IRepository<Contact> contactRepository, IRepository<Message> messageRepository)
        {
            Check.Require(contactRepository != null, "contact repository should not be null");
            Check.Require(messageRepository != null, "message repository should not be null");

            this.contactRepository = contactRepository;
            this.messageRepository = messageRepository;
        }

        public ActionResult List()
        {
            var contacts = contactRepository.FindAll(Order.Desc("Name"));

            return View("List", contacts);
        }

        public ActionResult New()
        {
            return RedirectToAction<ContactsController>(c => c.Edit(null));
        }

        public ActionResult Edit(int? id)
        {
            var contact = id.HasValue ? contactRepository.Load(id.Value) : null;

            ViewData["Contact"] = contact;

            return View();
        }

        public JsonResult ContactNameAvailable([Deserialize("Contact")] Contact contact)
        {
            return new JsonResult
                   {
                       Data = ContactWithSameNameExists(contact.Name) ? false : true
                   };
        }

        private bool ContactWithSameNameExists(string contactName)
        {
            return contactRepository.Exists(DetachedCriteria.For<Contact>()
                                                .Add(Restrictions.Eq("Name", contactName)));
        }

        [Transaction]
        public ActionResult CreateOrUpdate([Deserialize("Contact")] Contact contact)
        {
            Check.Require(contact != null, "contact should not be null");

            if(!ContactWithSameNameExists(contact.Name))
                contactRepository.SaveOrUpdate(contact);

            return RedirectToAction<ContactsController>(c => c.List());
        }

        [Transaction]
        public ActionResult Delete(int id)
        {
            Check.Require(id > 0, "id must be greater than 0, repository cannot delete a transient object");

            var contact = contactRepository.Load(id);

            var messagesWithContactAsSenderOrReceiver =
                DetachedCriteria
                    .For<Message>()
                    .Add(new OrExpression(Property
                                              .ForName("Sender")
                                              .Eq(contact),
                                          Property
                                              .ForName("Receiver")
                                              .Eq(contact)));

            if (messageRepository.Exists(messagesWithContactAsSenderOrReceiver))
                TempData["Error"] =
                    string.Format("Contact {0} cannot be deleted because there are messages sent or received by it.",
                                  contact.Name);
            else
                contactRepository.Delete(contact);

            return RedirectToAction<ContactsController>(c => c.List());
        }
    }
}